package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"xmediaEmu/pkg/decoder"
	"xmediaEmu/pkg/decoder/codec"
	"xmediaEmu/pkg/decoder/codec/amrparser"
)

// test amr.
func main() {
	if len(os.Args) < 2 {
		fmt.Println("Please provide a audio file")
		os.Exit(1)
	}

	// var amrcodeData amrparser.AmrNbCodecData
	var amrcodeData amrparser.AmrWbCodecData
	amrDecoder, err := decoder.NewAudioDecoderByName(amrcodeData)
	if err != nil {
		panic(err)
	}
	//_ = amrDecoder.SetChannelLayout(codec.CH_MONO)
	//_ = amrDecoder.SetBitrate(24000)
	//_ = amrDecoder.SetSampleRate(16000)
	//_ = amrDecoder.SetSampleFormat(codec.S16)
	//
	//// 初始化编码.
	//if err = amrDecoder.Setup(); err != nil {
	//	panic(err)
	//}
	reSampler := &decoder.Resampler{
		OutSampleFormat:  codec.S16,
		OutSampleRate:    8000,
		OutChannelLayout: codec.CH_MONO,
	}

	fileBuf, err := ioutil.ReadFile(os.Args[1])
	if err != nil {
		fmt.Printf("Unable to open file %s, error: %s\n", os.Args[1], err.Error())
		os.Exit(1)
	}

	// 只针对amr的一个帧，rtp传输的需要去掉CMR和F等填充bit.
	var amrPayloader AmrPayloader
	payloadAmr := amrPayloader.PayloadAmrWB(fileBuf)

	// 一帧帧解析.
	for _, pkt := range payloadAmr {
		// 1024成一帧.
		frameResult, err := amrDecoder.DecodingMultipleFrame(pkt, reSampler)
		if err != nil && len(frameResult) <= 0 {
			fmt.Printf("Decode amr result  err:%v\n", err)
			continue
		}
		for index, frame := range frameResult {
			fmt.Printf("Decode amr result length is: index:%v frameResult.Data[0]:length:%d frameResult.Data:length:%d err:%v\n", index, len(frame.Data[0]), len(frame.Data), err)
		}

	}

	got, frameResult, err := amrDecoder.ReceiveReserved()
	for len(frameResult.Data) > 0 {
		{
			fmt.Printf("Decode amr result length is: got:%v frameResult.Data[0]:length:%d frameResult.Data:length:%d err:%v\n", got, len(frameResult.Data[0]), len(frameResult.Data), err)
			got, frameResult, err = amrDecoder.ReceiveReserved()
		}
	}

	amrDecoder.Close()
}

// amr nb 和wb的文件帧类型
/*
var amr_nbFrameLen = []int{95, 103, 118, 134, 148, 159, 204, 244, 39}
var wbSpeechFrameBytes = []int{18, 23, 33, 37, 41, 47, 51, 59, 61, 0, 0, 0, 0, 0, 0, 0}
var CMR = []byte{1, 1, 1, 1}

type AmrPayloader struct{}

// RTP里的一帧,
func (p *AmrPayloader) PayloadAmr(amr_data []byte) (amrPayLoad [][]byte) {
	amr_data = amr_data[6:]
	amr_data = Bytes2Bits(amr_data)
	for index := 0; index < len(amr_data); {
		payload := make([]byte, 0)
		// payload = append(payload, CMR...)                       //CMR
		payload = append(payload, 0)                            //F
		payload = append(payload, amr_data[index+1:index+6]...) //FT和Q
		flen := amr_nbFrameLen[int((amr_data[index+1]<<3)+(amr_data[index+2]<<2)+(amr_data[index+3]<<1)+amr_data[index+4])]
		payload = append(payload, amr_data[index+8:index+flen+8]...) //payloaddata
		for num := 8 - len(payload)%8; 0 < num && num < 8; num-- {   //8位对齐补0
			payload = append(payload, 0)
		}
		amrPayLoad = append(amrPayLoad, Bits2Bytes(payload))
		index += 8 + flen
		for num := 8 - flen%8; 0 < num && num < 8; num-- {
			index += 1
		}
	}
	return amrPayLoad
}

func (p *AmrPayloader) PayloadAmrWB(amr_data []byte) (amrPayLoad [][]byte) {
	var frame []byte
	amr_data = amr_data[9:]
	for current, length := 0, len(amr_data); current < length; {
		index := 0
		ft := amr_data[current] >> 3
		next := current + wbSpeechFrameBytes[ft]
		frame = make([]byte, wbSpeechFrameBytes[ft])
		frame[index] = (8 << 4) | (amr_data[current] >> 4)
		frame[index+1] = (amr_data[current] << 4) | (amr_data[current+1] >> 2)
		index += 2
		for current += 2; current < next; current++ {
			frame[index] = (amr_data[current-1] << 6) | (amr_data[current] >> 2)
			index++
		}
		amrPayLoad = append(amrPayLoad, frame)
	}
	return amrPayLoad
}

func Bytes2Bits(data []byte) []byte {
	bin := make([]byte, 0)
	for _, v := range data {
		for i := 0; i < 8; i++ {
			move := uint(7 - i)
			bin = append(bin, uint8((v>>move)&1))
		}
	}
	return bin
}

// 二进制数组转字节数组
func Bits2Bytes(data []byte) []byte {
	bytes := make([]byte, 0)
	for i := 0; i < len(data); i += 8 {
		bytes = append(bytes, (data[i]<<7)+(data[i+1]<<6)+(data[i+2]<<5)+
			(data[i+3]<<4)+(data[i+4]<<3)+(data[i+5]<<2)+(data[i+6]<<1)+(data[i+7]))
	}
	return bytes
}
*/
